package com.iotechn.unimall.app.api.card;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.iotechn.unimall.app.config.ezviz.EzvizService;
import com.iotechn.unimall.biz.service.user.UserBizService;
import com.iotechn.unimall.core.exception.AppServiceException;
import com.iotechn.unimall.core.exception.ExceptionDefinition;
import com.iotechn.unimall.core.exception.ServiceException;
import com.iotechn.unimall.core.exception.ThirdPartServiceException;
import com.iotechn.unimall.core.util.DateUtils;
import com.iotechn.unimall.core.util.GeneratorUtil;
import com.iotechn.unimall.data.component.CacheComponent;
import com.iotechn.unimall.data.component.LockComponent;
import com.iotechn.unimall.data.domain.*;
import com.iotechn.unimall.data.enums.OrderStatusType;
import com.iotechn.unimall.data.enums.UserCardStatusType;
import com.iotechn.unimall.data.enums.UserLoginType;
import com.iotechn.unimall.data.mapper.*;
import com.iotechn.unimall.data.model.Page;
import com.iotechn.unimall.data.util.SessionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;


@Service
public class CardOrderServiceImpl implements CardOrderService {

    private static final Logger logger = LoggerFactory.getLogger(CardOrderServiceImpl.class);

    private static final String TAKE_ORDER_LOCK = "TAKE_TREE_ORDER_";

    @Value("${com.iotechn.unimall.machine-no}")
    private String MACHINE_NO;
    @Value("${com.iotechn.unimall.env}")
    private String ENV;
    @Value("${com.iotechn.unimall.wx.mini.app-id}")
    private String wxMiNiAppid;
    @Value("${com.iotechn.unimall.wx.app.app-id}")
    private String wxAppAppid;
    @Value("${com.iotechn.unimall.wx.h5.app-id}")
    private String wxH5Appid;

    @Autowired
    private CardOrderMapper cardOrderMapper;
    @Autowired
    private UserCardMapper userCardMapper;
    @Autowired
    private CardOrderDetailMapper cardOrderDetailsMapper;
    @Autowired
    private AddressMapper addressMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LockComponent lockComponent;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private UserBizService userBizService;
    @Autowired
    private CacheComponent cacheComponent;

    @Autowired
    private CardMapper cardMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String takeOrder(CardOrderDO cardOrderDO, String channel, Long userId) throws ServiceException {
        //加上乐观锁，防止用户重复提交订单
        if (lockComponent.tryLock(TAKE_ORDER_LOCK + userId, 20)) {
            try {
                if (cardOrderDO.getTotalPrice() <= 0)
                    throw new AppServiceException(ExceptionDefinition.ORDER_PRICE_MUST_GT_ZERO);
                if (cardOrderDO.getAddressId() == null)
                    throw new AppServiceException(ExceptionDefinition.ORDER_ADDRESS_CANNOT_BE_NULL);

                Date now = new Date();
                CardOrderDO orderDo = new CardOrderDO();
                // 获取订单号
                String orderNo = GeneratorUtil.genOrderId(MACHINE_NO, ENV);
                orderDo.setChannel(channel);
                orderDo.setActualPrice(cardOrderDO.getTotalPrice());
                orderDo.setCardOrderNo(orderNo);
                orderDo.setCardUserId(userId);
                orderDo.setStatus(OrderStatusType.UNPAY.getCode());
                orderDo.setGmtUpdate(now);
                orderDo.setGmtCreate(now);
                orderDo.setActualPrice(cardOrderDO.getTotalPrice());
                // set address
                if (cardOrderDO.getAddressId() != null) {
                    AddressDO addressDO = addressMapper.selectById(cardOrderDO.getAddressId());
                    if (!userId.equals(addressDO.getUserId()))
                        throw new AppServiceException(ExceptionDefinition.ORDER_ADDRESS_NOT_BELONGS_TO_YOU);
                    orderDo.setConsignee(addressDO.getConsignee());
                    orderDo.setPhone(addressDO.getPhone());
                    orderDo.setProvince(addressDO.getProvince());
                    orderDo.setCity(addressDO.getCity());
                    orderDo.setCounty(addressDO.getCounty());
                    orderDo.setAddress(addressDO.getAddress());
                }
                if(cardOrderMapper.insert(orderDo)>0)
                // 插入到详情表
                {
                    CardDO cardDO=cardMapper.selectById(cardOrderDO.getCardId());
                        UserCardDO userCardDO = new UserCardDO();
                        userCardDO.setCardId(cardDO.getId());
                        userCardDO.setCardNo(cardDO.getCardNo());
                        userCardDO.setTitle(cardDO.getTitle());
                        userCardDO.setActivateTime(now);
                        userCardDO.setGmtStart(now);
                        userCardDO.setStatus(UserCardStatusType.ACTIVE.getCode());
                        //userCardDO.setGmtEnd(DateUtils.);
                        userCardDO.setMoney(cardDO.getMoney());
                        userCardDO.setAllStock(cardDO.getAllStock());
                        userCardDO.setCurStock(cardDO.getAllStock());
                        userCardDO.setStatus(1);
                        userCardDO.setUsageTime(now);
                        userCardDO.setUserId(userId);
                        userCardDO.setGmtUpdate(now);
                        userCardDO.setUsageTime(now);
                        userCardDO.setGmtCreate(now);
                         Integer count = userCardMapper.insert(userCardDO);
                }

                return orderNo;
            } catch (ServiceException e) {
                throw e;
            } catch (Exception e) {
                logger.error("[提交订单] 异常", e);
                throw new AppServiceException(ExceptionDefinition.ORDER_UNKNOWN_EXCEPTION);
            } finally {
                lockComponent.retree(TAKE_ORDER_LOCK + userId);
            }
        }
        throw new AppServiceException(ExceptionDefinition.ORDER_SYSTEM_BUSY);
    }


    @Override
    public Page<CardOrderDO> list(Integer page, Integer limit, Long userId) throws ServiceException {
        EntityWrapper<CardOrderDO> wrapper = new EntityWrapper<>();
        if (userId!=null) {
            wrapper.eq("user_id", userId);
        }
        Integer count = cardOrderMapper.selectCount(wrapper);
        List<CardOrderDO> cardOrderDOS = cardOrderMapper.selectList(wrapper);
        return new Page<CardOrderDO>(cardOrderDOS, page, limit, count);
    }

    /**
     * 订单详情
     * @param cardOrderId
     * @param userId
     * @return
     * @throws ServiceException
     */
    @Override
    public CardOrderDO detail(Long cardOrderId, Long userId) throws ServiceException {
        CardOrderDO cardOrderDO = cardOrderMapper.selectById(cardOrderId);
        return cardOrderDO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object wxPrepay(String orderNo, String ip, Long userId) throws ServiceException {
        Date now = new Date();
        Wrapper<CardOrderDO> wrapper = new EntityWrapper<CardOrderDO>()
                .eq("card_order_no", orderNo).eq("card_user_id", userId);
        List<CardOrderDO> orderDOS = cardOrderMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(orderDOS))
            throw new AppServiceException(ExceptionDefinition.ORDER_NOT_EXIST);
        CardOrderDO orderDO = orderDOS.get(0);
        // 检测订单状态
        if (orderDO.getStatus() != OrderStatusType.UNPAY.getCode()) {
            throw new AppServiceException(ExceptionDefinition.ORDER_STATUS_NOT_SUPPORT_PAY);
        }

        Integer loginType = SessionUtil.getUser().getLoginType();
        String appId;
        String tradeType;
        if (UserLoginType.MP_WEIXIN.getCode() == loginType) {
            appId = wxMiNiAppid;
            tradeType = WxPayConstants.TradeType.JSAPI;
        } else if (UserLoginType.APP_WEIXIN.getCode() == loginType || UserLoginType.REGISTER.getCode() == loginType) {
            appId = wxAppAppid;
            tradeType = WxPayConstants.TradeType.APP;
        } else if (UserLoginType.H5_WEIXIN.getCode() == loginType) {
            appId = wxH5Appid;
            tradeType = WxPayConstants.TradeType.JSAPI;
        } else {
            throw new AppServiceException(ExceptionDefinition.ORDER_LOGIN_TYPE_NOT_SUPPORT_WXPAY);
        }

        Object result ;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setAppid(appId);
            orderRequest.setOutTradeNo(orderNo);
            orderRequest.setOpenid(SessionUtil.getUser().getOpenId());
            orderRequest.setBody("订单：" + orderNo);
            orderRequest.setTotalFee(orderDO.getActualPrice());
            orderRequest.setSpbillCreateIp(ip);
            orderRequest.setTradeType(tradeType);
            result = wxPayService.createOrder(orderRequest);
            if (result instanceof WxPayMpOrderResult) {
                String prepayId = ((WxPayMpOrderResult)result).getPackageValue();
                prepayId = prepayId.replace("prepay_id=", "");
                UserFormIdDO userFormIdDO = new UserFormIdDO();
                userFormIdDO.setFormId(prepayId);
                userFormIdDO.setUserId(userId);
                userFormIdDO.setOpenid(SessionUtil.getUser().getOpenId());
                userFormIdDO.setGmtUpdate(now);
                userFormIdDO.setGmtCreate(now);
                userBizService.setValidFormId(userFormIdDO);
            }
        } catch (WxPayException e) {
            logger.error("[微信支付] 异常", e);
            throw new ThirdPartServiceException(e.getErrCodeDes(), ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
        } catch (Exception e) {
            logger.error("[预付款异常]", e);
            throw new AppServiceException(ExceptionDefinition.ORDER_UNKNOWN_EXCEPTION);
        }
        return result;
    }

}
